package com.easyjava.builder;

import com.easyjava.bean.Constants;
import com.easyjava.bean.FieldInfo;
import com.easyjava.bean.TableInfo;
import com.easyjava.init.InitCascade;
import com.easyjava.utils.MyStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

import static com.easyjava.init.InitCascade.TABLE_INFO_MAP;

/**
 * @Author: 小闹心
 * @Description: 创建控制器类
 * @DateTime: 2024/11/20 18:01
 **/
public class BuildController {
    private static final Logger logger = LoggerFactory.getLogger(BuildController.class);

    public static void execute(TableInfo tableInfo){
        File folder = new File(Constants.PATH_CONTROLLER);
        if(!folder.exists()){
            folder.mkdirs();
        }
        String className = tableInfo.getBeanName() + "Controller";
        File file = new File(folder, className + ".java");
        OutputStream out = null;
        OutputStreamWriter outWriter = null;
        BufferedWriter bw = null;
        try{
            out = new FileOutputStream(file);
            outWriter = new OutputStreamWriter(out, StandardCharsets.UTF_8);
            bw = new BufferedWriter(outWriter);
            bw.write("package " + Constants.PACKAGE_CONTROLLER + ";");
            bw.newLine();
            bw.newLine();
            bw.write("import " + Constants.PACKAGE_COMMON + ".Result;");
            bw.newLine();
            bw.write("import " + Constants.PACKAGE_PO + "." + tableInfo.getBeanName() + ";");
            bw.newLine();
            bw.write("import " + Constants.PACKAGE_QUERY + "." + tableInfo.getBeanParamName() + ";");
            bw.newLine();
            bw.write("import " + Constants.PACKAGE_VO + ".PaginationResultVO;");
            bw.newLine();
            // 生成连表查询方法,导入连表查询的查询类
            String tableName = tableInfo.getTableName();
            List<String> tablesList = InitCascade.CASCADE_TABLE_MAP.get(tableName);
            if(tablesList != null){
                // String fields = InitCascade.CASCADE_FIELD_RELATION_MAP.get(tables);
                for(String tables : tablesList){
                    String[] tablesArray = tables.split(",");
                    for(int i = 1; i < tablesArray.length; i++){
                        bw.write("import " + Constants.PACKAGE_QUERY + "." + InitCascade.TABLE_INFO_MAP.get(tablesArray[i]).getBeanName() + Constants.SUFFIX_BEAN_QUERY + ";");
                        bw.newLine();
                    }


                    StringBuilder cascadeClass = new StringBuilder();
                    String[] cascadeTable = tables.split(",");
                    cascadeClass.append(MyStringUtils.upperCaseFirstLetter(cascadeTable[0]));
                    if(cascadeTable.length > 1){
                        cascadeClass.append("And");
                    }
                    for(int i = 1; i < cascadeTable.length;i++){
                        cascadeClass.append(MyStringUtils.upperCaseFirstLetter(TABLE_INFO_MAP.get(cascadeTable[i]).getBeanName()));
                        if(i != cascadeTable.length - 1){
                            cascadeClass.append("And");
                        }
                    }
                    bw.write("import " + Constants.PACKAGE_VO + "." + cascadeClass + ";");
                    bw.newLine();
                }
                bw.write("import java.util.List;");
                bw.newLine();
            }
            String serviceName = tableInfo.getBeanName() + "Service";
            bw.write("import " + Constants.PACKAGE_SERVICE + "." + serviceName + ";");
            bw.newLine();
            if(Constants.KNIFE4J_ENABLE){
                bw.write("import io.swagger.v3.oas.annotations.Operation;");
                bw.newLine();
                bw.write("import io.swagger.v3.oas.annotations.tags.Tag;");
                bw.newLine();
            }
            bw.write("import org.springframework.web.bind.annotation.*;");
            bw.newLine();
            bw.newLine();
            bw.write("import org.springframework.beans.factory.annotation.Autowired;");
            bw.newLine();
            bw.newLine();
            // 生成类注释
            String serviceBeanName = MyStringUtils.lowerCaseFirstLetter(serviceName);
            BuildComment.createClassComment(bw,tableInfo.getComment() + "Controller");
            if(Constants.KNIFE4J_ENABLE){
                bw.write("@Tag(name = \"" + tableInfo.getComment() + "Controller" + "\")");
                bw.newLine();
            }
            bw.write("@RestController");
            bw.newLine();
            String beanName = MyStringUtils.lowerCaseFirstLetter(tableInfo.getBeanName());
            bw.write("@RequestMapping(\"/" + beanName +  "\")");
            bw.newLine();
            bw.write("public class " + className + " {");
            bw.newLine();
            bw.newLine();
            bw.write("\t@Autowired");
            bw.newLine();
            bw.write("\tprivate " + serviceName + " " + serviceBeanName + ";");
            bw.newLine();
            bw.newLine();

            // 分页查询
            bw.write("\t/**");
            bw.newLine();
            bw.write("\t * 分页查询");
            bw.newLine();
            String beanParamName = MyStringUtils.lowerCaseFirstLetter(tableInfo.getBeanParamName());
            bw.write("\t * @param " + beanParamName + " 查询条件");
            bw.newLine();
            bw.write("\t * @return 分页查询结果");
            bw.newLine();
            bw.write("\t*/");
            bw.newLine();
            if(Constants.KNIFE4J_ENABLE){
                bw.write("\t@Operation(summary = \"分页查询\")");
                bw.newLine();
            }
            bw.write("\t@GetMapping(\"/list\")");
            bw.newLine();
            bw.write("\tpublic Result<PaginationResultVO<" + tableInfo.getBeanName()
                    + ">> get" + tableInfo.getBeanName() + "ByPage("
                    + tableInfo.getBeanParamName() + " " + beanParamName + "){");
            bw.newLine();
            bw.write("\t\tPaginationResultVO<" + tableInfo.getBeanName() + "> listByPage = " +
                    serviceBeanName + ".findListByPage(" + beanParamName + ");");
            bw.newLine();
            bw.write("\t\treturn Result.ok(listByPage);");
            bw.newLine();
            bw.write("\t}");
            bw.newLine();
            bw.newLine();


            //新增数据
            bw.write("\t/**");
            bw.newLine();
            bw.write("\t * 新增数据");
            bw.newLine();
            bw.write("\t * @param " + beanName + " 新增数据");
            bw.newLine();
            bw.write("\t * @return 操作结果");
            bw.newLine();
            bw.write("\t*/");
            bw.newLine();
            if(Constants.KNIFE4J_ENABLE){
                bw.write("\t@Operation(summary = \"新增数据\")");
                bw.newLine();
            }
            bw.write("\t@PostMapping(\"/insert\")");
            bw.newLine();
            bw.write("\tpublic Result<String> add" + tableInfo.getBeanName()
                    + "(" + tableInfo.getBeanName() + " " + beanName +"){");
            bw.newLine();
            bw.write("\t\tInteger i = " + serviceBeanName + ".addOne(" + beanName + ");");
            bw.newLine();
            bw.write("\t\treturn i > 0 ? Result.ok(\"新增数据成功\") : Result.ok(\"新增数据失败\");");
            bw.newLine();
            bw.write("\t}");
            bw.newLine();
            bw.newLine();

            //修改数据
            bw.write("\t/**");
            bw.newLine();
            bw.write("\t * 修改数据");
            bw.newLine();
            bw.write("\t * @param " + beanName + " 修改数据");
            bw.newLine();
            bw.write("\t * @return 操作结果");
            bw.newLine();
            bw.write("\t*/");
            bw.newLine();
            if(Constants.KNIFE4J_ENABLE){
                bw.write("\t@Operation(summary = \"修改数据\")");
                bw.newLine();
            }
            bw.write("\t@PutMapping(\"/update\")");
            bw.newLine();
            bw.write("\tpublic Result<String> update" + tableInfo.getBeanName()
                    + "(" + tableInfo.getBeanName() + " " + beanName +"){");
            bw.newLine();
            Map<String, List<FieldInfo>> keyIndexMap = tableInfo.getKeyIndexMap();
            List<FieldInfo> fieldInfos = keyIndexMap.get("PRIMARY");
            FieldInfo primaryKey = fieldInfos.get(0);

            bw.write("\t\tInteger i = " + serviceBeanName + ".updateBy" + MyStringUtils.upperCaseFirstLetter(primaryKey.getPropertyName())  + "(" + beanName + "," + beanName + ".get" +
                    MyStringUtils.upperCaseFirstLetter(primaryKey.getPropertyName()) + "());");
            bw.newLine();
            bw.write("\t\treturn i > 0 ? Result.ok(\"修改数据成功\") : Result.ok(\"修改数据失败\");");
            bw.newLine();
            bw.write("\t}");
            bw.newLine();
            bw.newLine();

            // 生成唯一索引方法
            for(Map.Entry<String, List<FieldInfo>> entry : keyIndexMap.entrySet()){
                List<FieldInfo> keyFields = entry.getValue();
                Integer index = 0;
                // getBy xxx方法
                StringBuilder methodName = new StringBuilder();
                // 方法参数 带类型
                StringBuilder methodParam = new StringBuilder();
                // 方法参数 不带类型
                StringBuilder execParam = new StringBuilder();
                // 方法注释 参数注释
                StringBuilder paramComment = new StringBuilder();
                for(FieldInfo fieldInfo : keyFields){
                    index++;
                    methodName.append(MyStringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName()));
                    methodParam.append(fieldInfo.getJavaType() + " " + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()));
                    paramComment.append(fieldInfo.getComment() == null ? " " : fieldInfo.getComment());
                    execParam.append(MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()));
                    if(index < keyFields.size()){
                        methodName.append("And");
                        methodParam.append(", ");
                        execParam.append(", ");
                        paramComment.append(", ");
                    }
                }

                // 查询数据
                bw.write("\t/**");
                bw.newLine();
                bw.write("\t * 根据" + methodName + "查询数据");
                bw.newLine();
                bw.write("\t * @param " + execParam + " [" + paramComment + "]");
                bw.newLine();
                bw.write("\t * @return 查询结果");
                bw.newLine();
                bw.write("\t*/");
                bw.newLine();
                if(Constants.KNIFE4J_ENABLE){
                    bw.write("\t@Operation(summary = \"根据" + methodName + "查询数据" + "\")");
                    bw.newLine();
                }
                bw.write("\t@GetMapping(\"/getBy" + methodName + "\")");
                bw.newLine();
                bw.write("\tpublic " + tableInfo.getBeanName() + " getBy" + methodName + "(" + methodParam+ ") {");
                bw.newLine();
                bw.write("\t\treturn " + serviceBeanName + ".getBy" + methodName + "(" + execParam + ");");
                bw.newLine();
                bw.write("\t}");
                bw.newLine();
                bw.newLine();

                // 修改数据
                bw.write("\t/**");
                bw.newLine();
                bw.write("\t * 根据" + methodName + "修改数据");
                bw.newLine();
                bw.write("\t * @param " + beanName + " 更新的数据信息");
                bw.write("\t * @param " + execParam + " [" + paramComment + "]");
                bw.newLine();
                bw.write("\t * @return 操作结果");
                bw.newLine();
                bw.write("\t*/");
                bw.newLine();
                if(Constants.KNIFE4J_ENABLE){
                    bw.write("\t@Operation(summary = \"根据" + methodName + "修改数据" + "\")");
                    bw.newLine();
                }
                bw.write("\t @PostMapping(\"/updateBy" + methodName +"\")");
                bw.newLine();
                bw.write("\tpublic Result<String> updateBy" + methodName + "("
                        + tableInfo.getBeanName() + " " + beanName + ", " + methodParam +") {");
                bw.newLine();
                bw.write("\t\tInteger i = " + serviceBeanName + ".updateBy" + methodName + "(" + beanName +", " + execParam + ");");
                bw.newLine();
                bw.write("\t\treturn i > 0 ? Result.ok(\"更新成功\") : Result.ok(\"更新失败\");");
                bw.newLine();
                bw.write("\t}");
                bw.newLine();
                bw.newLine();

                // 删除数据
                bw.write("\t/**");
                bw.newLine();
                bw.write("\t * 根据" + methodName + "删除数据");
                bw.newLine();
                bw.write("\t * @param " + execParam + " [" + paramComment + "]");
                bw.newLine();
                bw.write("\t * @return 操作结果");
                bw.newLine();
                bw.write("\t*/");
                bw.newLine();
                if(Constants.KNIFE4J_ENABLE){
                    bw.write("\t@Operation(summary = \"根据" + methodName + "删除数据" + "\")");
                    bw.newLine();
                }
                bw.write("\t@DeleteMapping(\"/deleteBy" + methodName + "\")");
                bw.newLine();
                bw.write("\tpublic Result<String> deleteBy" + methodName + "(" + methodParam + ") {");
                bw.newLine();
                bw.write("\t\tInteger i = " + serviceBeanName + ".deleteBy" + methodName + "(" + execParam + ");");
                bw.newLine();
                bw.write("\t\treturn i > 0 ? Result.ok(\"删除成功\") : Result.ok(\"删除失败\");");
                bw.newLine();
                bw.write("\t}");
                bw.newLine();
                bw.newLine();


            }
            // 创建连表查询方法
            if(tablesList != null) {
                for (String tables : tablesList) {
                    StringBuilder cascadeClass = new StringBuilder();
                    String[] cascadeTable = tables.split(",");
                    cascadeClass.append(MyStringUtils.upperCaseFirstLetter(cascadeTable[0]));
                    if (cascadeTable.length > 1) {
                        cascadeClass.append("And");
                    }
                    for (int i = 1; i < cascadeTable.length; i++) {
                        cascadeClass.append(MyStringUtils.upperCaseFirstLetter(TABLE_INFO_MAP.get(cascadeTable[i]).getBeanName()));
                        if (i != cascadeTable.length - 1) {
                            cascadeClass.append("And");
                        }
                    }
                    // 创建连表查询方法
                    bw.write("\t/**");
                    bw.newLine();
                    bw.write("\t * " + cascadeClass + "连表查询");
                    bw.newLine();
                    for (int i = 0; i < cascadeTable.length; i++){
                        TableInfo curTable = TABLE_INFO_MAP.get(cascadeTable[i]);
                        bw.write("\t * @param " + MyStringUtils.lowerCaseFirstLetter(curTable.getBeanName()) + " [" + curTable.getComment() + "查询条件]");
                        bw.newLine();
                    }
                    bw.write("\t * @return 查询结果");
                    bw.newLine();
                    bw.write("\t*/");
                    bw.newLine();
                    if(Constants.KNIFE4J_ENABLE){
                        bw.write("\t@Operation(summary = \"" + cascadeClass + "连表查询" + "\")");
                        bw.newLine();
                    }
                    bw.write("\t@GetMapping(\"/get" + cascadeClass + "\")");
                    bw.newLine();
                    bw.write("\tpublic Result<List<" + cascadeClass + ">> " + "select" + cascadeClass + "(");
                    for (int i = 0; i < cascadeTable.length; i++) {
                        String bufBeanName = TABLE_INFO_MAP.get(cascadeTable[i]).getBeanName();
                        bw.write(MyStringUtils.upperCaseFirstLetter(bufBeanName) + Constants.SUFFIX_BEAN_QUERY + " " + MyStringUtils.lowerCaseFirstLetter(bufBeanName));
                        if (i != cascadeTable.length - 1) {
                            bw.write(", ");
                        }
                    }
                    bw.write(") {");
                    bw.newLine();
                    bw.write("\t\treturn Result.ok(" + serviceBeanName + ".select" + cascadeClass + "(");
                    for (int i = 0; i < cascadeTable.length; i++) {
                        bw.write(MyStringUtils.lowerCaseFirstLetter(TABLE_INFO_MAP.get(cascadeTable[i]).getBeanName()));
                        if (i != cascadeTable.length - 1) {
                            bw.write(", ");
                        }
                    }
                    bw.write("));");
                    bw.newLine();
                    bw.write("\t}");
                    bw.newLine();
                }
            }
            bw.write("}");
            bw.flush();
        }catch (Exception e){
            logger.error("创建{}对象失败" , className);
        }finally {
            if(bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outWriter != null){
                try {
                    outWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
